/** 
 * @Title:工具类 
 * @Desription:统计报表帮助类
 * @Company:CSN
 * @ClassName:ChartHelper.java
 * @Author:Mengfh
 * @CreateDate:2013-11-15   
 * @UpdateUser:Mengfh
 * @Version:0.1 
 *    
 */ 

package com.midian.common.utils;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.apache.struts2.json.JSONException;
import org.apache.struts2.json.JSONUtil;

import com.midian.model.common.vo.report.ChartVo;
import com.midian.model.common.vo.report.ReportGroupVo;
import com.midian.model.common.vo.report.ReportVo;

/** 
 * @ClassName: ChartHelper 
 * @Description: 统计报表帮助类 
 * @author: Mengfh
 * @date: 2013-11-15
 * 
 */
public class ChartHelper {
	/**log4j日志对象*/
	private static Logger logger = Logger.getLogger(ChartHelper.class);
	//统计报表类型
	/**统计报表类型，饼图*/
	public static final String PIE = "pie";
	/**统计报表类型，柱状图(横向)*/
	public static final String BAR = "bar";
	/**统计报表类型，柱状图(纵向)*/
	public static final String COLUMN = "column";
	/**统计报表类型，折线图*/
	public static final String LINE = "line";
	//对象转换字段key
	/**对象转换字段key，X轴名称字段key*/
	public static final String XAXISCOLNAME = "xaxisColName";
	/**对象转换字段key，组名称字段key*/
	public static final String GROUPCOLNAME = "groupColName";
	/**对象转换字段key，Y轴数值字段key*/
	public static final String VALCOLNAME = "valColName";
	/**指定组名称，不从字段获取*/
	public static final String DEFGROUPNAME = "defGroupName";
	/**指定X轴名称,不从字段获取*/
	public static final String DEFXAXISNAME = "defXaxisName";
	//组名称
	/**组名称：总体*/
	public static final String GROUPNAME_ALL = "总体";
	/**组名称：1级*/
	public static final String GROUPNAME_LEVELONE = "1级";
	/**组名称：2级*/
	public static final String GROUPNAME_LEVELTWO = "2级";
	/**组名称：3级*/
	public static final String GROUPNAME_LEVELTHREE = "3级";
	/**组名称：技术类*/
	public static final String GROUPNAME_TECH = "技术类";
	/**组名称：规范类*/
	public static final String GROUPNAME_STAN = "规范类";
	//组颜色设置
	/**组颜色设置：总体*/
	public static final String COLOR_ALL = "#CC99FF";
	/**组颜色设置：1级*/
	public static final String COLOR_LEVELONE = "#CCFF33";
	/**组颜色设置：2级*/
	public static final String COLOR_LEVELTWO = "#FFCC99";
	/**组颜色设置：3级*/
	public static final String COLOR_LEVELTHREE = "#FF99CC";
	/**组颜色设置：技术类*/
	public static final String COLOR_TECH = "#87CEFA";
	/**组颜色设置：规范类*/
	public static final String COLOR_STAN = "#66CDAA";
	
	//报表对象JSON字符串的标记
	/**报表对象JSON字符串的标记：fn的开始*/
	public static final String JSON_MARK_FN_BEGIN = "json_mark_fn_begin";
	/**报表对象JSON字符串的标记：fn的结束*/
	public static final String JSON_MARK_FN_END = "json_mark_fn_end";
	
	/**
	 * 获取属性(链)值
	 * @param obj 目标对象
	 * @param property 属性名称
	 * @return
	 */
	private static Object getPropertyValue(Object obj, String property) {
		if(obj == null || StringUtils.isBlank(property)) {
			return null;
		}
		//如果对象是Map类型，直接获取Map中对应key的value值
		if(obj instanceof Map) {
			Map map = (Map) obj;
			return map.get(property);
		}
		//如果不是Map类型，通过属性的get方法获取其值
		String[] propertyChain = property.split("\\."); //获取属性链
		Object result = null;
		for (String pro : propertyChain) {
			if(obj == null){
				break;
			}
			String methodName = "get" + pro.substring(0, 1).toUpperCase() + pro.substring(1);
			Class objClass = obj.getClass();
			try {
				Method method = objClass.getMethod(methodName, null);
				result = method.invoke(obj, null);
				if(result != null){
					String resultStr = result.toString().trim();
					if(!resultStr.equals("")){
						obj = result;
						continue;
					}
				}
				result = null;
				obj = null;
			} catch (Exception e) {
				logger.error(e.getMessage());
			}
		}
		return result;
	}
	
	/**
	 * 创建生成图表的Chart对象
	 * @param chartVo chart数据对象
	 * @param dataList 目标数据集合
	 * @param propMap 目标数据对应的字段Map
	 * @return
	 */
	public static ChartVo createOpChartVo(ChartVo chartVo, List dataList, Map<String, String> propMap) {
		List<Map<String, String>> propMapList = new ArrayList<Map<String,String>>();
		propMapList.add(propMap);
		return createOpChartVo(chartVo, dataList, propMapList);
	}
	
	/**
	 * 创建生成图表的Chart对象
	 * @param chartVo chart数据对象
	 * @param dataList 目标数据集合
	 * @param propMapList 目标数据对应的字段Map集合
	 * @return
	 */
	public static ChartVo createOpChartVo(ChartVo chartVo, List dataList, List<Map<String, String>> propMapList) {
		if(dataList == null || dataList.isEmpty() || propMapList == null || propMapList.isEmpty()) {
			return null;
		}
		//X轴名称Map
		Map<String, Number> xaxisNameMap = new LinkedHashMap<String, Number>();
		//组对象Map
		Map<String, Map<String, Number>> rptGrpMap = new LinkedHashMap<String, Map<String,Number>>();
		for (Object obj : dataList) {
			for(Map<String, String> propMap : propMapList) {
				String xaxisName = ""; //X轴名称
				String defXaxisName = propMap.get(DEFXAXISNAME);
				if(StringUtils.isNotBlank(defXaxisName)) {
					//如果有指定X轴名称,直接获取,不需要通过字段反射
					xaxisName = defXaxisName;
				} else {
					//如果没有指定X轴名称，通过字段进行反射获取
					xaxisName = String.valueOf(getPropertyValue(obj, propMap.get(XAXISCOLNAME))); //根据X轴对应字段获取X轴的名称
				}
				String groupName = ""; //组名称
				String defGroupName = propMap.get(DEFGROUPNAME);
				if(StringUtils.isNotBlank(defGroupName)) {
					//如果有指定组名称，直接获取，不需要通过字段反射
					groupName = defGroupName;
				} else {
					//如果没有指定组名称，通过字段进行反射获取，如果设置字段名为空，指定组名称为总体
					String groupColName = propMap.get(GROUPCOLNAME); //组对应字段名称
					if(StringUtils.isNotBlank(groupColName)) {
						groupName = String.valueOf(getPropertyValue(obj, groupColName)); //根据组对应字段获取组的名称
					} else {
						groupName = GROUPNAME_ALL; //总体
					}
				}
				Number val = null;
				try {
					Object srcVal = getPropertyValue(obj, propMap.get(VALCOLNAME));
					if (srcVal instanceof String) {
						//如果是字符串类型，根据整形或者浮点型进行转换
						if(chartVo.getIsDataInteger()) {
							val = Integer.parseInt(String.valueOf(srcVal));
						} else {
							val = Double.parseDouble(String.valueOf(srcVal));
						}
					} else {
						//如果是数字类型，直接转换
						val = (Number) srcVal; //根据Y轴对应字段获取Y轴的数值
					}
				} catch (ClassCastException e) {
					logger.error(e.getMessage());
				}
				//保存X轴名称(没保存过的才进行保存，去掉重复)
				if(!xaxisNameMap.containsKey(xaxisName)) {
					xaxisNameMap.put(xaxisName, null);
				}
				Map<String, Number> rptGrpDataMap = null;
				if(!rptGrpMap.containsKey(groupName)) {
					//如果当前组没进行过保存，新建当前组
					rptGrpDataMap = new LinkedHashMap<String, Number>();
					rptGrpMap.put(groupName, rptGrpDataMap);
				} else {
					//如果当前组已经进行过保存，直接获取当前组
					rptGrpDataMap = rptGrpMap.get(groupName);
				}
				//保存统计节点数据
				rptGrpDataMap.put(xaxisName, val);
			}
		}
		//统计节点组对象List
		List<ReportGroupVo> reportGroupVoList = new ArrayList<ReportGroupVo>();
		for(Entry<String, Map<String, Number>> rptGrpEntry : rptGrpMap.entrySet()) {
			String groupName = rptGrpEntry.getKey(); //组名称
			Map<String, Number> rptGrpDataMap = rptGrpEntry.getValue(); //组中的节点数据Map
			//根据X轴名称Map，生成一个组节点数据为空的初始化Map
			Map<String, Number> rptGrpDataInitMap = new LinkedHashMap<String, Number>();
			//如果X轴不是数字类型的情况，才需要初始化X轴名称全列表
			if(!chartVo.getIsXaxisNumber()) {
				//需要根据组和X轴补空的情况,生成一个组节点数据为空的初始化Map
				rptGrpDataInitMap.putAll(xaxisNameMap);
			}
			//填充组中所拥有的统计节点数据(填充动作使得X轴没有对应数据的点继续保持空值，以达到X轴对应数据点的补空)
			rptGrpDataInitMap.putAll(rptGrpDataMap);
			//封装统计节点组对象
			ReportGroupVo reportGroupVo = new ReportGroupVo();
			//设置组名称
			reportGroupVo.setGroupName(groupName);
			//统计节点VO对象List
			List<ReportVo> reportVoList = new ArrayList<ReportVo>();
			for(Entry<String, Number> rptGrpDataInitEntry : rptGrpDataInitMap.entrySet()) {
				//封装统计节点VO对象
				ReportVo reportVo = new ReportVo();
				reportVo.setName(rptGrpDataInitEntry.getKey()); //X轴名称
				reportVo.setCount(rptGrpDataInitEntry.getValue()); //Y轴数值
				reportVoList.add(reportVo);
			}
			//设置统计节点VO对象List
			reportGroupVo.setReportVoList(reportVoList);
			reportGroupVoList.add(reportGroupVo);
		}
		//X轴名称List
		List<String> xaxisNameList = new ArrayList<String>();
		for(String xaxisName : xaxisNameMap.keySet()) {
			xaxisNameList.add(xaxisName);
		}
		//设置X轴名称List
		chartVo.setXaxisNameList(xaxisNameList);
		//设置统计节点组对象List
		chartVo.setReportGroupVoList(reportGroupVoList);
		//如果X轴显示的是数值，并且有指定X轴显示的最大个数，将X轴的值升序，
		//根据X轴显示的最大个数获取X轴的值，并将这个值设置为X轴显示的最大值
		if(chartVo.getIsXaxisNumber()) {
			Integer xaxisMaxCount = chartVo.getXaxisMaxCount(); //X轴显示的个数
			if(xaxisMaxCount != null && !xaxisNameList.isEmpty()) {
				List<Double> xaxisValList = new ArrayList<Double>();
				for (String xaxisName : xaxisNameList) {
					try {
						xaxisValList.add(Double.parseDouble(xaxisName));
					} catch (NumberFormatException e) {
						logger.error(e.getMessage());
					}
				}
				Collections.sort(xaxisValList); //将X轴的值进行升序
				int xaxisValListSize = xaxisValList.size();
				int index = 0;
				if(xaxisMaxCount > xaxisValListSize) {
					//如果设置的X轴显示的最大个数大于X轴数值集合个数，X轴显示的最大值设置为X轴数值集合的最后一个值
					index = xaxisValListSize - 1;
				} else {
					//如果设置的X轴显示的最大个数不大于X轴数值集合个数，根据X轴显示的最大个数来获取X轴的数值并设置为X轴显示的最大值
					index = xaxisMaxCount - 1;
				}
				chartVo.setXaxisMaxVal(xaxisValList.get(index));
			}
		}
		return chartVo;
	}
	
	/**
	 * 将多个报表VO对象整合为一个对象(用于报表混合类型图)
	 * @param chartVoList 报表VO对象集合
	 * @return
	 */
	public static ChartVo mergeToOneChartVo(List<ChartVo> chartVoList) {
		ChartVo targetChartVo = null;
		List<ReportGroupVo> targetReportGroupVoList = new ArrayList<ReportGroupVo>();
		if(chartVoList != null && !chartVoList.isEmpty()) {
			targetChartVo = chartVoList.get(0);
			for (ChartVo chartVo : chartVoList) {
				List<ReportGroupVo> reportGroupVoList = chartVo.getReportGroupVoList(); //组集合
				if(reportGroupVoList != null && !reportGroupVoList.isEmpty()) {
					//将组的报表类型设置为报表VO对象的类型(用于报表混合类型图设置报表类型)
					for (ReportGroupVo reportGroupVo : reportGroupVoList) {
						reportGroupVo.setGroupType(chartVo.getType());
					}
				}
				targetReportGroupVoList.addAll(reportGroupVoList); //整合组集合
			}
			targetChartVo.setReportGroupVoList(targetReportGroupVoList);
		}
		return targetChartVo;
	}
	
	/**
	 * 创建柱状图的plotOptions属性的JSON设置
	 * @param chartVo 报表VO对象
	 * @return
	 */
	private static Map<String, Object> createBarAndColPlotOptionsMap(ChartVo chartVo) {
		//报表统计组列表
		List<ReportGroupVo> reportGroupVoList = chartVo.getReportGroupVoList();
		String type = chartVo.getType(); //统计报表类型
		String yaxisUnitDesc = chartVo.getYaxisUnitDesc(); //Y轴描述
		/*柱状图的plotOptions属性设置*/
		Map<String, Object> barAndColPlotOptionsMap = new HashMap<String, Object>();
		barAndColPlotOptionsMap.put("pointPadding", 0.2);
		barAndColPlotOptionsMap.put("borderWidth", 0);
		//柱状图的plotOptions中的dataLabels设置
		Map<String, Object> barAndColPlotOptions_dataLabelsMap = new HashMap<String, Object>();
		barAndColPlotOptions_dataLabelsMap.put("enabled", true);
		barAndColPlotOptions_dataLabelsMap.put("color", "#000");
		barAndColPlotOptions_dataLabelsMap.put("format", "{point.y}" + yaxisUnitDesc);
		//如果有指定柱状图统计节点的数值的字体大小，进行字体大小的设置
		String plotOptionsFontSize = chartVo.getPlotOptionsFontSize();
		if(StringUtils.isNotBlank(plotOptionsFontSize)) {
			Map<String, Object> barAndColPlotOptions_dataLabels_styleMap = new HashMap<String, Object>();
			barAndColPlotOptions_dataLabels_styleMap.put("fontSize", plotOptionsFontSize);
			barAndColPlotOptions_dataLabelsMap.put("style", barAndColPlotOptions_dataLabels_styleMap);
		}
		barAndColPlotOptionsMap.put("dataLabels", barAndColPlotOptions_dataLabelsMap);
		//如果统计类型为柱状图，并且只有一组统计数据的情况，如果统计节点数量不大于5，将柱宽调整为30
		//如果将多组整合为一组的情况，将柱宽设置为30
		if((COLUMN.equals(type) || BAR.equals(type)) && reportGroupVoList.size() == 1) {
			List<ReportVo> reportVoList = reportGroupVoList.get(0).getReportVoList();
			if(reportVoList.size() <= 5) {
				barAndColPlotOptionsMap.put("pointWidth", 30); //柱的宽度
			}
		}
		//如果将多组整合为一组的情况，将柱宽设置为30，每组的内边距设置为0.5
		if(chartVo.getIsMergeOneGroup()) {
			barAndColPlotOptionsMap.put("pointWidth", 30); //柱的宽度
			barAndColPlotOptionsMap.put("groupPadding", 0.5); //设置每组的内边距
		}
		return barAndColPlotOptionsMap;
	}
	
	/**
	 * 创建折线图的plotOptions属性的JSON设置
	 * @param chartVo 报表VO对象
	 * @return
	 */
	private static Map<String, Object> createLinePlotOptionsMap(ChartVo chartVo) {
		String yaxisUnitDesc = chartVo.getYaxisUnitDesc(); //Y轴描述
		/*折线图的plotOptions属性设置*/
		Map<String, Object> linePlotOptionsMap = new HashMap<String, Object>();
		//折线图的plotOptions中的dataLabels设置
		Map<String, Object> linePlotOptions_dataLabelsMap = new HashMap<String, Object>();
		linePlotOptions_dataLabelsMap.put("enabled", chartVo.getIsLineDataLabelsShow()); //是否显示折线点的数据
		linePlotOptions_dataLabelsMap.put("color", "#000");
		linePlotOptions_dataLabelsMap.put("format", "{point.y}" + yaxisUnitDesc);
		//如果有指定折线图统计节点的数值的字体大小，进行字体大小的设置
		String plotOptionsFontSize = chartVo.getPlotOptionsFontSize();
		if(StringUtils.isNotBlank(plotOptionsFontSize)) {
			Map<String, Object> linePlotOptions_dataLabels_styleMap = new HashMap<String, Object>();
			linePlotOptions_dataLabels_styleMap.put("fontSize", plotOptionsFontSize);
			linePlotOptions_dataLabelsMap.put("style", linePlotOptions_dataLabels_styleMap);
		}
		linePlotOptionsMap.put("dataLabels", linePlotOptions_dataLabelsMap);
		linePlotOptionsMap.put("enableMouseTracking", true); //鼠标移动到统计点时的提示开关
		linePlotOptionsMap.put("lineWidth", 1); //设置线宽
		//折线点设置
		Map<String, Object> linePlotOptions_markerMap = new HashMap<String, Object>();
		linePlotOptions_markerMap.put("enabled", chartVo.getIsMarker()); //是否显示折线图的点
		linePlotOptions_markerMap.put("radius", 3); //设置点的半径
		//折线图不需要显示点的情况
		if(!chartVo.getIsMarker()) {
			linePlotOptions_markerMap.put("radius", 0); //设置点的半径为零
			linePlotOptions_markerMap.put("lineColor", "{series.color}"); //设置点边框的颜色为当前线的颜色
			linePlotOptions_markerMap.put("lineWidth", 0);
			//统计节点提示信息设置
			Map<String, Object> linePlotOptions_tooltipMap = new HashMap<String, Object>();
			linePlotOptions_tooltipMap.put("headerFormat", "{series.name}：");
			linePlotOptions_tooltipMap.put("pointFormat", "{point.y}" + yaxisUnitDesc);
			linePlotOptionsMap.put("tooltip", linePlotOptions_tooltipMap);
		}
		linePlotOptionsMap.put("marker", linePlotOptions_markerMap);
		//如果需要屏蔽线条，进行线的隐藏
		if(chartVo.getIsHideLine()) {
			linePlotOptionsMap.put("lineWidth", 0);
		}
		return linePlotOptionsMap;
	}
	
	/**
	 * 创建饼图的plotOptions属性的JSON设置
	 * @param chartVo 报表VO对象
	 * @return
	 */
	private static Map<String, Object> createPiePlotOptionsMap(ChartVo chartVo) {
		String yaxisUnitDesc = chartVo.getYaxisUnitDesc(); //Y轴描述
		/*饼图的plotOptions属性设置*/
		Map<String, Object> piePlotOptionsMap = new HashMap<String, Object>();
		piePlotOptionsMap.put("allowPointSelect", true);
		piePlotOptionsMap.put("cursor", "pointer");
		//饼图的dataLabels设置
		Map<String, Object> piePlotOptions_dataLabelsMap = new HashMap<String, Object>();
		piePlotOptions_dataLabelsMap.put("enabled", true);
		piePlotOptions_dataLabelsMap.put("color", "#000");
		piePlotOptions_dataLabelsMap.put("connectorColor", "#000");
		piePlotOptions_dataLabelsMap.put("format", "<b>{point.name}</b>：{point.y}" + yaxisUnitDesc);
		//如果有指定饼图统计节点的数值的字体大小，进行字体大小的设置
		String plotOptionsFontSize = chartVo.getPlotOptionsFontSize();
		if(StringUtils.isNotBlank(plotOptionsFontSize)) {
			Map<String, Object> piePlotOptions_dataLabels_styleMap = new HashMap<String, Object>();
			piePlotOptions_dataLabels_styleMap.put("fontSize", plotOptionsFontSize);
			piePlotOptions_dataLabelsMap.put("style", piePlotOptions_dataLabels_styleMap);
		}
		piePlotOptionsMap.put("dataLabels", piePlotOptions_dataLabelsMap);
		piePlotOptionsMap.put("showInLegend", chartVo.getIsLegend()); //是否显示饼图图例
		return piePlotOptionsMap;
	}
	
	/**
	 * 获取X轴属性的JSON设置
	 * @param chartVo 报表VO对象
	 * @return
	 */
	private static Map<String, Object> createXAxisOptionsMap(ChartVo chartVo) {
		/*X轴属性设置*/
		Map<String, Object> xAxisOptionsMap = new HashMap<String, Object>();
		//如果X轴显示的是字符串，设置X轴名称集合
		if(!chartVo.getIsXaxisNumber()) {
			//获取X轴名称列表
			List<String> xaxisNameList = chartVo.getXaxisNameList();
			if(xaxisNameList != null && !xaxisNameList.isEmpty()) {
				xAxisOptionsMap.put("categories", xaxisNameList); //X轴名称集合
			}
		}
		//如果有设置X轴的刻度，进行设置
		Double xaxisTickInterval = chartVo.getXaxisTickInterval();
		if(xaxisTickInterval != null) {
			xAxisOptionsMap.put("tickInterval", xaxisTickInterval);
		}
		//X轴标题设置
		Map<String, Object> xAxisOptions_titleMap = new HashMap<String, Object>();
		xAxisOptions_titleMap.put("text", chartVo.getXaxisTitle()); //X轴标题
		//X轴标题样式设置
		Map<String, Object> xAxisOptions_title_styleMap = new HashMap<String, Object>();
		xAxisOptions_title_styleMap.put("color", "#000");
		xAxisOptions_title_styleMap.put("fontWeight", "bold");
		xAxisOptions_titleMap.put("style", xAxisOptions_title_styleMap);
		xAxisOptionsMap.put("title", xAxisOptions_titleMap);
		//X轴labels设置
		Map<String, Object> xAxisOptions_labelsMap = new HashMap<String, Object>();
		//X轴labels样式设置
		Map<String, Object> xAxisOptions_labels_styleMap = new HashMap<String, Object>();
		xAxisOptions_labels_styleMap.put("color", "#000");
		xAxisOptions_labels_styleMap.put("fontSize", "13px");
		xAxisOptions_labelsMap.put("style", xAxisOptions_labels_styleMap);
		xAxisOptions_labelsMap.put("rotation", -45);
		//如果不需要显示X轴，或者整合为一组的情况，屏蔽X轴显示
		if(!chartVo.getIsXaxisShow() || chartVo.getIsMergeOneGroup()) {
			xAxisOptions_labelsMap.put("enabled", false); //屏蔽X轴刻度值
			xAxisOptionsMap.put("lineWidth", 0); //X轴线宽度为0
			xAxisOptionsMap.put("tickWidth", 0); //X轴刻度宽度为0
		}
		xAxisOptionsMap.put("labels", xAxisOptions_labelsMap);
		//X轴显示的最大值(用于左右滚动报表)
		Double xaxisMaxVal = chartVo.getXaxisMaxVal();
		if(xaxisMaxVal != null) {
			xAxisOptionsMap.put("max", xaxisMaxVal);
		}
		return xAxisOptionsMap;
	}
	
	/**
	 * 获取Y轴属性的JSON设置
	 * @param chartVo 报表VO对象
	 * @return
	 */
	private static Map<String, Object> createYAxisOptionsMap(ChartVo chartVo) {
		String yaxisUnitDesc = chartVo.getYaxisUnitDesc(); //Y轴描述
		/*Y轴属性设置*/
		Map<String, Object> yAxisOptionsMap = new HashMap<String, Object>();
		//Y轴标题设置
		Map<String, Object> yAxisOptions_titleMap = new HashMap<String, Object>();
		yAxisOptions_titleMap.put("text", chartVo.getYaxisTitle()); //Y轴标题
		//Y轴标题样式设置
		Map<String, Object> yAxisOptions_title_styleMap = new HashMap<String, Object>();
		yAxisOptions_title_styleMap.put("color", "#000");
		yAxisOptions_title_styleMap.put("fontWeight", "bold");
		yAxisOptions_titleMap.put("style", yAxisOptions_title_styleMap);
		yAxisOptionsMap.put("title", yAxisOptions_titleMap);
		//Y轴labels设置
		Map<String, Object> yAxisOptions_labelsMap = new HashMap<String, Object>();
		//Y轴labels样式设置
		Map<String, Object> yAxisOptions_labels_styleMap = new HashMap<String, Object>();
		yAxisOptions_labels_styleMap.put("color", "#000");
		yAxisOptions_labelsMap.put("style", yAxisOptions_labels_styleMap);
		yAxisOptions_labelsMap.put("formatter", JSON_MARK_FN_BEGIN + "function() {return this.value + '" + yaxisUnitDesc + "'}" + JSON_MARK_FN_END);
		//如果不需要显示Y轴，屏蔽Y轴显示
		if(!chartVo.getIsYaxisShow()) {
			yAxisOptions_labelsMap.put("enabled", false);
		}
		yAxisOptionsMap.put("labels", yAxisOptions_labelsMap);
		//Y轴的最小值(默认值为0，如果设置为null即恢复自动设置)
		yAxisOptionsMap.put("min", chartVo.getYaxisMinVal());
		//如果显示的是整型数据，禁用Y轴的小数显示
		if(chartVo.getIsDataInteger()) {
			yAxisOptionsMap.put("allowDecimals", false);
		}
		//Y轴的最大值
		Double yaxisMaxVal = chartVo.getYaxisMaxVal();
		if(yaxisMaxVal != null) {
			yAxisOptionsMap.put("max", yaxisMaxVal);
		}
		//Y轴的刻度
		Double yaxisTickInterval = chartVo.getYaxisTickInterval();
		if(yaxisTickInterval != null) {
			yAxisOptionsMap.put("tickInterval", yaxisTickInterval);
		}
		return yAxisOptionsMap;
	}
	
	/**
	 * 获取HighCharts所需的数据对象集合
	 * @param chartVo 报表VO对象
	 * @return
	 */
	private static List<Map<String, Object>> createSeriesMapList(ChartVo chartVo) {
		String type = chartVo.getType(); //统计报表类型
		List<Map<String, Object>> seriesMapList = new ArrayList<Map<String,Object>>();
		List<ReportGroupVo> reportGroupVoList = chartVo.getReportGroupVoList();
		if(!reportGroupVoList.isEmpty()) {
			for (ReportGroupVo reportGroupVo : reportGroupVoList) {
				String groupName = reportGroupVo.getGroupName(); //组名称
				String color = reportGroupVo.getColor(); //组颜色
				String groupType = reportGroupVo.getGroupType(); //组对应的报表类型
				Boolean visible = reportGroupVo.getVisible(); //组的隐藏属性
				List<Object[]> dataList = new ArrayList<Object[]>(); //统计节点数据集合
				List<ReportVo> reportVoList = reportGroupVo.getReportVoList(); //统计节点集合
				if(!reportVoList.isEmpty()) {
					for (ReportVo reportVo : reportVoList) {
						String name = reportVo.getName(); //统计节点名称
						Number count = null;
						if(chartVo.getIsDataInteger()) {
							count = reportVo.getIntegerCount(); //显示整型数据
						} else {
							if(chartVo.getIsRealVal()) {
								count = reportVo.getRealDoubleCount(); //显示浮点型数据
							} else {
								count = reportVo.getDoubleCount(); //显示浮点型数据(两位小数四舍五入)
							}
						}
						dataList.add(new Object[]{name, count});
					}
				}
				//数据对象
				Map<String, Object> dataObjMap = new HashMap<String, Object>();
				dataObjMap.put("name", groupName);
				dataObjMap.put("visible", visible);
				dataObjMap.put("data", dataList);
				//如果设置了组颜色，进行颜色设置(由于饼图没分组，不需要进行组颜色设置)
				if(!PIE.equals(type) && StringUtils.isNotBlank(color)) {
					dataObjMap.put("color", color);
				}
				//如果设置了组的报表类型，进行报表类型的设置
				if(StringUtils.isNotBlank(groupType)) {
					dataObjMap.put("type", groupType);
				}
				seriesMapList.add(dataObjMap);
			}
		}
		return seriesMapList;
	}
	
	/**
	 * 获取HighCharts报表对象
	 * @param chartVo 报表VO对象
	 * @param optionsMap 属性设置Map集合
	 * @return
	 */
	private static Map<String, Object> createHighChartsMap(ChartVo chartVo, Map<String, Map<String, Object>> optionsMap) {
		String type = chartVo.getType(); //统计报表类型
		Integer width = chartVo.getWidth(); //显式指定的统计报表的宽度
		Integer height = chartVo.getHeight(); //显式指定的统计报表的高度
		String yaxisUnitDesc = chartVo.getYaxisUnitDesc(); //Y轴描述
		//报表统计组列表
		List<ReportGroupVo> reportGroupVoList = chartVo.getReportGroupVoList();
		//数据点提示信息中的组名称
		String headerMsg = ""; //数据点提示的头部信息
		//如果不是整合为同一组的情况，并且统计组对象集合数大于1，证明出现多个统计组，数据点提示信息需要加上组名称前缀
		if(!chartVo.getIsMergeOneGroup() && reportGroupVoList.size() > 1) {
			headerMsg = "{series.name}，"; //series.name为组名称
		}
		//获取属性设置Map
		Map<String, Object> barAndColPlotOptionsMap = optionsMap.get("barAndColPlotOptionsMap"); //获取柱状图的plotOptions属性设置
		Map<String, Object> linePlotOptionsMap = optionsMap.get("linePlotOptionsMap"); //获取折线图的plotOptions属性设置
		Map<String, Object> piePlotOptionsMap = optionsMap.get("piePlotOptionsMap"); //获取饼图的plotOptions属性设置
		Map<String, Object> xAxisOptionsMap = optionsMap.get("xAxisOptionsMap"); //获取X轴属性设置
		Map<String, Object> yAxisOptionsMap = optionsMap.get("yAxisOptionsMap"); //获取Y轴属性设置
		//HighCharts报表对象JSON属性设置
		Map<String, Object> highChartsMap = new LinkedHashMap<String, Object>();
		/*HighCharts的scrollbar设置*/
		Map<String, Object> highCharts_scrollbarMap = new HashMap<String, Object>();
		highCharts_scrollbarMap.put("enabled", chartVo.getIsScroll()); //是否需要左右滚动报表
		highChartsMap.put("scrollbar", highCharts_scrollbarMap);
		/*HighCharts的chart设置*/
		Map<String, Object> highCharts_chartMap = new HashMap<String, Object>();
		highCharts_chartMap.put("type", type); //报表类型
		if(width != null) {
			highCharts_chartMap.put("width", width); //显式指定的统计报表的宽度
		}
		if(height != null) {
			highCharts_chartMap.put("height", height); //显式指定的统计报表的高度
		}
		highChartsMap.put("chart", highCharts_chartMap);
		/*HighCharts的colors设置*/
		String[] colors = {
			"#003377", "#AA4643", "#89A54E", "#80699B", "#3D96AE", "#DB843D", "#666666", "#FFA07A", "#B5CA92",
			"#FFBB00", "#33FF33", "#0000FF", "#FF0000", "#FF00FF", "#B8860B", "#92A8CD", "#8B4513", "#000000", "006400"
		};
		highChartsMap.put("colors", colors);
		/*HighCharts的图例设置*/
		Map<String, Object> highCharts_legendMap = new HashMap<String, Object>();
		highCharts_legendMap.put("enabled", chartVo.getIsLegend()); //是否显示图例
		highCharts_legendMap.put("itemMarginTop", 2); //图例顶部margin
		highCharts_legendMap.put("itemMarginBottom", 2); //图例底部margin
		//需要设置图例在右上方的设置
		if(chartVo.getIsNeLegend()) {
			highCharts_legendMap.put("align", "right"); //水平对齐居右
			highCharts_legendMap.put("verticalAlign", "top"); //垂直对齐居上
			highCharts_legendMap.put("floating", true); //图例浮动
			//highCharts_legendMap.put("y", 50); //图例Y坐标值(绝对定位的top)
		}
		highChartsMap.put("legend", highCharts_legendMap);
		/*HighCharts的标题设置*/
		Map<String, Object> highCharts_titleMap = new HashMap<String, Object>();
		highCharts_titleMap.put("text", chartVo.getTitle()); //报表标题
		//HighCharts标题的样式设置
		Map<String, Object> highCharts_title_styleMap = new HashMap<String, Object>();
		//报表标题默认字体大小为20px
		String titleFontSize = "20px";
		//如果有指定标题字体大小的情况，进行设置
		if(StringUtils.isNotBlank(chartVo.getTitleFontSize())) {
			titleFontSize = chartVo.getTitleFontSize();
		}
		highCharts_title_styleMap.put("fontSize", titleFontSize);
		highCharts_title_styleMap.put("fontWeight", "bold");
		highCharts_title_styleMap.put("color", "#000");
		highCharts_titleMap.put("style", highCharts_title_styleMap);
		highChartsMap.put("title", highCharts_titleMap);
		/*HighCharts的副标题设置*/
		Map<String, Object> highCharts_subTitleMap = new HashMap<String, Object>();
		highCharts_subTitleMap.put("text", chartVo.getSubTitle()); //报表副标题
		//HighCharts副标题的样式设置
		Map<String, Object> highCharts_subTitle_styleMap = new HashMap<String, Object>();
		highCharts_subTitle_styleMap.put("color", "#000");
		highCharts_subTitleMap.put("style", highCharts_subTitle_styleMap);
		highChartsMap.put("subtitle", highCharts_subTitleMap);
		/*HighCharts的X轴设置*/
		highChartsMap.put("xAxis", xAxisOptionsMap);
		/*HighCharts的Y轴设置*/
		highChartsMap.put("yAxis", yAxisOptionsMap);
		/*HighCharts的统计节点提示设置*/
		Map<String, Object> highCharts_toolTipMap = new HashMap<String, Object>();
		highCharts_toolTipMap.put("headerFormat", headerMsg + "{point.key}："); //统计组名称(可无)，X轴名称
		highCharts_toolTipMap.put("pointFormat", "{point.y}" + yaxisUnitDesc); //X轴数值(可无)，Y轴数值
		highChartsMap.put("tooltip", highCharts_toolTipMap);
		/*HighCharts的统计节点对象设置*/
		Map<String, Object> highCharts_plotOptionsMap = new HashMap<String, Object>();
		highCharts_plotOptionsMap.put("bar", barAndColPlotOptionsMap); //柱状图(横向)节点数据显示设置
		highCharts_plotOptionsMap.put("column", barAndColPlotOptionsMap); //柱状图(纵向)节点数据显示设置
		highCharts_plotOptionsMap.put("line", linePlotOptionsMap); //折线图节点数据显示设置
		highCharts_plotOptionsMap.put("pie", piePlotOptionsMap); //饼图节点数据显示设置
		highChartsMap.put("plotOptions", highCharts_plotOptionsMap);
		/*HighCharts的报表数据集合设置*/
		List<Map<String, Object>> seriesMapList = createSeriesMapList(chartVo);
		highChartsMap.put("series", seriesMapList);
		/*HighCharts的插件版权资料设置*/
		Map<String, Object> highCharts_creditsMap = new HashMap<String, Object>();
		highCharts_creditsMap.put("enabled", false); //插件显示网址隐藏
		highChartsMap.put("credits", highCharts_creditsMap);
		return highChartsMap;
	}
	
	/**
	 * 获取HighCharts报表对象JSON字符串
	 * @param chartVo 报表VO对象
	 * @return
	 */
	public static String getHighChartJsonStr(ChartVo chartVo) {
		if(chartVo == null) {
			return "";
		}
		//柱状图的plotOptions属性设置
		Map<String, Object> barAndColPlotOptionsMap = createBarAndColPlotOptionsMap(chartVo);
		//折线图的plotOptions属性设置
		Map<String, Object> linePlotOptionsMap = createLinePlotOptionsMap(chartVo);
		//饼图的plotOptions属性设置
		Map<String, Object> piePlotOptionsMap = createPiePlotOptionsMap(chartVo);
		//非饼图，即柱状图、折线图，需要设置X、Y轴属性
		Map<String, Object> xAxisOptionsMap = null; //X轴属性
		Map<String, Object> yAxisOptionsMap = null; //Y轴属性
		if(!PIE.equals(chartVo.getType())) {
			xAxisOptionsMap = createXAxisOptionsMap(chartVo);
			yAxisOptionsMap = createYAxisOptionsMap(chartVo);
		}
		Map<String, Map<String, Object>> optionsMap = new HashMap<String, Map<String,Object>>();
		optionsMap.put("barAndColPlotOptionsMap", barAndColPlotOptionsMap); //柱状图的plotOptions属性设置
		optionsMap.put("linePlotOptionsMap", linePlotOptionsMap); //折线图的plotOptions属性设置
		optionsMap.put("piePlotOptionsMap", piePlotOptionsMap); //饼图的plotOptions属性设置
		optionsMap.put("xAxisOptionsMap", xAxisOptionsMap); //X轴属性设置
		optionsMap.put("yAxisOptionsMap", yAxisOptionsMap); //Y轴属性设置
		//获取HighCharts报表对象
		Map<String, Object> highChartsMap = createHighChartsMap(chartVo, optionsMap);
		String highChartsJsonStr = "";
		try {
			highChartsJsonStr = JSONUtil.serialize(highChartsMap);
		} catch (JSONException e) {
			logger.error(e.getMessage());
		}
		//将function前面的双引号和function结束的"}"后的双引号去掉
		if(!"".equals(highChartsJsonStr)) {
			String[] searchList = {"\"" + JSON_MARK_FN_BEGIN, JSON_MARK_FN_END + "\""};
			String[] replacementList = {"", ""};
			highChartsJsonStr = StringUtils.replaceEach(highChartsJsonStr, searchList, replacementList);
		}
		return highChartsJsonStr;
	}
	
	/*public static void main(String[] args) {
		ChartVo chartVo = new ChartVo(LINE, "测试", "副标题测试", "X轴", "Y轴", false, "%", true);
		ReportVo reportVo1 = new ReportVo();
		reportVo1.setName("张三");
		reportVo1.setCount(1);
		ReportVo reportVo2 = new ReportVo();
		reportVo2.setName("李四");
		reportVo2.setCount(2);
		ReportVo reportVo3 = new ReportVo();
		reportVo3.setName("王五");
		reportVo3.setCount(3);
		List<ReportVo> reportVoList = new ArrayList<ReportVo>();
		reportVoList.add(reportVo1);
		reportVoList.add(reportVo2);
		reportVoList.add(reportVo3);
		
		List<ReportGroupVo> reportGroupVoList = new ArrayList<ReportGroupVo>();
		ReportGroupVo reportGroupVo = new ReportGroupVo();
		reportGroupVo.setGroupName("CAN");
		reportGroupVo.setReportVoList(reportVoList);
		reportGroupVoList.add(reportGroupVo);
		
		chartVo.setReportGroupVoList(reportGroupVoList);
		chartVo.setIsMarker(false);
		//System.out.println(getHighChartJsonStr(chartVo));
	}*/
}